#include "KPage.h"
#include "KDef.h"
#include "KStorage.h"
#include <algorithm>
#include <cstring>

KPage::KPage(size_t pageSize)
    : m_data(NULL), m_size(pageSize > 0 ? pageSize : KDef::DefaultChunkSize)
{
    clear();
}

void KPage::free()
{
    if (m_data) {
        freeMemory(m_data);
        m_data = NULL;
        clear();
    }
}

bool KPage::reset()
{
    if (!m_data) {
        if (void *data = allocMemory()) {
            m_data = static_cast<BytePtr>(data);
        }
    }
    clear();
    return m_data != NULL;
}

size_t KPage::peek(void *dest, size_t length)
{
    assert(dest != NULL);
    KLocker lock(*this);
    if (m_read) {
        size_t n = std::min<size_t>(length, bytesAvailable());
        if (n > 0) {
            memcpy(dest, m_read, n);
        }
        return n;
    }
    return 0;
}

size_t KPage::read(void *dest, size_t length)
{
    KLocker lock(*this);
    if (m_read) {
        size_t n = std::min<size_t>(length, bytesAvailable());
        if (n > 0) {
            if (dest) {
                memcpy(dest, m_read, n);
            }
            m_read += n;
            if (!bytesAvailable()) {
                clear();
            }
        }
        return n;
    }
    return 0;
}

size_t KPage::write(const void *src, size_t length)
{
    assert(src != NULL);
    KLocker lock(*this);
    if (m_write) {
        size_t n = std::min<size_t>(length, space());
        if (n > 0) {
            memcpy(m_write, src, n);
            m_write += n;
        }
        return n;
    }
    return 0;
}

size_t KPage::write(KStorage *src, size_t length)
{
    assert(src != NULL);
    KLocker lock(*this);
    if (m_write) {
        size_t n = std::min<size_t>(space(),
            std::min<size_t>(length, src->bytesAvailable()));
        if (n > 0) {
            src->read(m_write, n);
            m_write += n;
        }
        return n;
    }
    return 0;
}